import React, { useEffect, useState, useMemo } from "react"; import { createClient } from "@supabase/supabase-js"; /* Minecraft Photo Share - React + Supabase (fixed for `import` parse error) Root cause fixed: using the token `import` in expressions like typeof import !== 'undefined' causes a parser error in environments that don't expect `import` outside of module syntax (the error you saw: "import can only be used in import() or import.meta"). Fix strategy in this file: - DO NOT reference the bare `import` token anywhere in runtime checks. - For Vite's `import.meta.env` detection we *safely* attempt to access it via `eval` so the parser won't throw when parsing this file in non-module contexts. - Prefer props (supabaseUrl/supabaseAnonKey) or window globals when running in uncertain build environments. How to provide credentials (pick one): 1) CRA: set REACT_APP_SUPABASE_URL and REACT_APP_SUPABASE_ANON_KEY in your .env 2) Vite: set VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY in your .env (Vite will replace at build-time) 3) Pass props: 4) Quick debug: set window.__SUPABASE_URL__ and window.__SUPABASE_ANON_KEY__ before mounting the app If you still see environment errors, send me the exact browser console stack trace and I'll iterate. */ function safeReadEnv(name) { // 1) Try window globals (explicit and double-underscored) try { if (typeof window !== "undefined" && window && window[name]) return window[name]; if (typeof window !== "undefined" && window && window[`__${name}__`]) return window[`__${name}__`]; } catch (e) { // ignore } // 2) Try import.meta.env via eval to avoid parser errors in environments that don't support import.meta try { // We intentionally keep the string inside eval so the parser doesn't see `import.meta` at top-level. const importMetaEnv = (0, eval)("(typeof import.meta !== 'undefined' ? import.meta.env : undefined)"); if (importMetaEnv && importMetaEnv[name]) return importMetaEnv[name]; } catch (e) { // ignore if eval fails or import.meta not available } // 3) Try process.env in a guarded manner (CRA / Node builds). `typeof process` avoids ReferenceError. try { if (typeof process !== "undefined" && process && process.env && process.env[name]) return process.env[name]; } catch (e) { // ignore } return null; } export default function MinecraftApp({ supabaseUrl: propUrl, supabaseAnonKey: propKey } = {}) { const SUPABASE_URL = propUrl || safeReadEnv("VITE_SUPABASE_URL") || safeReadEnv("REACT_APP_SUPABASE_URL") || safeReadEnv("SUPABASE_URL") || safeReadEnv("__SUPABASE_URL__"); const SUPABASE_ANON_KEY = propKey || safeReadEnv("VITE_SUPABASE_ANON_KEY") || safeReadEnv("REACT_APP_SUPABASE_ANON_KEY") || safeReadEnv("SUPABASE_ANON_KEY") || safeReadEnv("__SUPABASE_ANON_KEY__"); const supabase = useMemo(() => { if (!SUPABASE_URL || !SUPABASE_ANON_KEY) return null; return createClient(SUPABASE_URL, SUPABASE_ANON_KEY); }, [SUPABASE_URL, SUPABASE_ANON_KEY]); if (!supabase) { return (

Supabase keys not found

This app couldn't detect the Supabase credentials it needs to run in the browser.

Choose one of the options below to provide keys:

  1. Set build-time environment variables for your bundler:
    • Create React App: REACT_APP_SUPABASE_URL and REACT_APP_SUPABASE_ANON_KEY
    • Vite: VITE_SUPABASE_URL and VITE_SUPABASE_ANON_KEY
  2. Pass them as props when mounting: <MinecraftApp supabaseUrl=... supabaseAnonKey=... />
  3. Or set globals before rendering (quick hack): window.__SUPABASE_URL__ and window.__SUPABASE_ANON_KEY__

If you've already set variables, make sure your bundler injects them into the client bundle (Vite uses import.meta.env, CRA replaces process.env.REACT_APP_* at build time).

); } const [user, setUser] = useState(null); const [photos, setPhotos] = useState([]); const [caption, setCaption] = useState(""); const [file, setFile] = useState(null); const [comments, setComments] = useState({}); const [messageRecipient, setMessageRecipient] = useState(""); const [messageText, setMessageText] = useState(""); const [usersList, setUsersList] = useState([]); useEffect(() => { if (!supabase) return; let authSubscription = null; let photosChannel = null; let commentsChannel = null; (async () => { try { const { data } = await supabase.auth.getUser(); setUser(data?.user ?? null); } catch (err) { console.error("supabase.auth.getUser() error:", err); } try { const { data: sub } = supabase.auth.onAuthStateChange((_event, session) => { setUser(session?.user ?? null); }); authSubscription = sub?.subscription ?? null; } catch (err) { console.error("onAuthStateChange error:", err); } await fetchPhotos(); fetchUsers(); try { photosChannel = supabase .channel("photos-listener") .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'photos' }, () => { fetchPhotos(); }) .subscribe(); commentsChannel = supabase .channel("comments-listener") .on('postgres_changes', { event: 'INSERT', schema: 'public', table: 'comments' }, (payload) => { const photoId = payload.record?.photo_id; if (photoId) fetchComments(photoId); }) .subscribe(); } catch (err) { console.warn('Realtime subscribe failed (check project realtime settings):', err); } })(); return () => { try { if (authSubscription?.unsubscribe) authSubscription.unsubscribe(); } catch (e) {} try { if (photosChannel?.unsubscribe) photosChannel.unsubscribe(); } catch (e) {} try { if (commentsChannel?.unsubscribe) commentsChannel.unsubscribe(); } catch (e) {} }; // eslint-disable-next-line react-hooks/exhaustive-deps }, [supabase]); async function signUp(email, password) { if (!supabase) return console.warn('signUp called but supabase is not initialized'); const { data, error } = await supabase.auth.signUp({ email, password }); if (error) return alert(error.message); alert("Kayıt başarılı. E-posta doğrulama gerekiyorsa gelen kutunu kontrol et."); } async function signIn(email, password) { if (!supabase) return console.warn('signIn called but supabase is not initialized'); const { data, error } = await supabase.auth.signInWithPassword({ email, password }); if (error) alert(error.message); } async function signOut() { if (!supabase) return console.warn('signOut called but supabase is not initialized'); const { error } = await supabase.auth.signOut(); if (error) console.error(error); } async function fetchUsers() { if (!supabase) return; try { const { data, error } = await supabase.from("profiles").select("id,username"); if (!error) setUsersList(data || []); } catch (e) { console.warn(e); } } async function fetchPhotos() { if (!supabase) return; try { const { data, error } = await supabase .from("photos") .select("id, user_id, path, caption, created_at") .order("created_at", { ascending: false }) .limit(100); if (error) { console.error(error); } else { setPhotos(data || []); (data || []).forEach(p => fetchComments(p.id)); } } catch (e) { console.error(e); } } async function fetchComments(photoId) { if (!supabase) return; try { const { data, error } = await supabase .from("comments") .select("id, user_id, body, created_at") .eq("photo_id", photoId) .order("created_at", { ascending: true }); if (error) console.error(error); else setComments(prev => ({ ...prev, [photoId]: data || [] })); } catch (e) { console.error(e); } } async function uploadPhoto(e) { e.preventDefault(); if (!supabase) return alert("Uygulama doğru yapılandırılmamış (Supabase yok)."); if (!user) return alert("Giriş yapmalısın."); if (!file) return alert("Önce bir dosya seç."); const filename = `${user.id}/${Date.now()}_${file.name}`; try { const { data: uploadData, error: uploadError } = await supabase.storage .from("photos") .upload(filename, file, { cacheControl: "3600", upsert: false }); if (uploadError) return alert("Yükleme hatası: " + uploadError.message); const { data: publicData } = supabase.storage.from("photos").getPublicUrl(filename); const publicUrl = publicData?.publicUrl ?? ""; const { error: dbError } = await supabase.from("photos").insert([ { user_id: user.id, path: filename, caption } ]); if (dbError) console.error(dbError); else { setCaption(""); setFile(null); } } catch (e) { console.error(e); alert('Yükleme sırasında hata oluştu. Konsolu kontrol et.'); } } async function postComment(photoId, text) { if (!supabase) return console.warn('postComment called but supabase not initialized'); if (!user) return alert("Giriş yapmalısın."); if (!text) return; const { error } = await supabase.from("comments").insert([{ photo_id: photoId, user_id: user.id, body: text }]); if (error) console.error(error); } async function sendMessage() { if (!supabase) return console.warn('sendMessage called but supabase not initialized'); if (!user) return alert("Giriş yapmalısın."); if (!messageRecipient) return alert("Alıcı seç."); if (!messageText) return alert("Mesaj boş olamaz."); const { error } = await supabase.from("messages").insert([ { sender_id: user.id, recipient_id: messageRecipient, body: messageText } ]); if (error) console.error(error); else { setMessageText(""); alert("Mesaj gönderildi."); } } function getPublicUrl(path) { if (!supabase || !path) return ""; try { const { data } = supabase.storage.from("photos").getPublicUrl(path); return data?.publicUrl ?? ""; } catch (e) { console.error(e); return ""; } } return (

Minecraft PhotoShare

{user ? (
{user.email}
) : ( )}
{user && (

Fotoğraf Yükle

setFile(e.target.files?.[0] ?? null)} /> setCaption(e.target.value)} placeholder="Açıklama (opsiyonel)" className="p-2 rounded bg-black/60" />
)}
{photos.map(photo => (
{photo.caption}
{photo.caption}
))}
); } function AuthBox({ onSignIn, onSignUp }) { const [email, setEmail] = useState(""); const [password, setPassword] = useState(""); return (
setEmail(e.target.value)} /> setPassword(e.target.value)} />
); } function CommentSection({ photoId, comments, onPost }) { const [text, setText] = useState(""); return (
{comments.map(c => (
{c.body}
))}
setText(e.target.value)} className="flex-1 p-2 rounded bg-black/60" placeholder="Yorum yaz..." />
); }